﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Globalization;
using System.Text;

using Recon.Portal.Business;
using Recon.Portal.DataObjects;

namespace Recon.Portal.WebUI
{
    public partial class AuthorizeInvoice : System.Web.UI.Page
    {
        //process type enumeration to determine the type of process being carried out.
        private enum ProcessType
        {
            Authorize,
            Reject,
            CancelAuthorization,
            CancelRejection
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                GetUnauthorizedInvoiceList();
            }
        }

        protected void grdAuthList_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            if (e.Row.RowIndex > -1)
            {
                DateTime dt;
                if (e.Row.Cells[2].Text != "" && e.Row.Cells[2].Text != "&nbsp;")
                {
                    dt = Convert.ToDateTime(e.Row.Cells[2].Text);
                    e.Row.Cells[2].Text = dt.ToString("dd-MM-yyyy");
                    e.Row.Cells[2].HorizontalAlign = HorizontalAlign.Center;
                }
                else
                {
                    e.Row.Cells[2].Text = "";
                }
                if (e.Row.Cells[6].Text != "" && e.Row.Cells[6].Text != "&nbsp;")
                {
                    dt = Convert.ToDateTime(e.Row.Cells[6].Text);
                    e.Row.Cells[6].Text = dt.ToString("dd-MM-yyyy");
                    e.Row.Cells[6].HorizontalAlign = HorizontalAlign.Center;
                }
                else
                {
                    e.Row.Cells[6].Text = "";
                }

                double value = 0.00;
                if (e.Row.Cells[4].Text != "" && e.Row.Cells[4].Text != "&nbsp;")
                {
                    value = Convert.ToDouble(e.Row.Cells[4].Text);
                    e.Row.Cells[4].Text = value.ToString("#,#.00", CultureInfo.InvariantCulture);
                    e.Row.Cells[4].HorizontalAlign = HorizontalAlign.Right;
                }
                else
                {
                    e.Row.Cells[4].Text = "0.00";
                }
                if (e.Row.Cells[8].Text != "" && e.Row.Cells[8].Text != "&nbsp;")
                {
                    value = Convert.ToDouble(e.Row.Cells[8].Text);
                    e.Row.Cells[8].Text = value.ToString("#,#.00", CultureInfo.InvariantCulture);
                    e.Row.Cells[8].HorizontalAlign = HorizontalAlign.Right;
                }
                else
                {
                    e.Row.Cells[8].Text = "0.00";
                }
            }
        }

        protected void grdAuthList_PageIndexChanging(object sender, GridViewPageEventArgs e)
        {
            grdAuthList.DataSource = (List<MatchedInvoice>)Session[SessionStore.UnAuthorizedList];
            grdAuthList.PageIndex = e.NewPageIndex;
            grdAuthList.DataBind();
        }

        protected void grdConfirmAuthorization_RowDataBound(object sender, GridViewRowEventArgs e)
        {

        }

        protected void grdConfirmRejection_RowDataBound(object sender, GridViewRowEventArgs e)
        {

        }

        protected void btnAuthorize_Click(object sender, EventArgs e)
        {
            ShowPopyp(ProcessType.Authorize);
        }

        protected void btnReject_Click(object sender, EventArgs e)
        {
            ShowPopyp(ProcessType.Reject);
        }

        protected void btnConfirmAuthorization_Click(object sender, EventArgs e)
        {
            ProcessInvoices(ProcessType.Authorize);
        }

        protected void btnCancelAuthorization_Click(object sender, EventArgs e)
        {
            ProcessInvoices(ProcessType.CancelAuthorization);
        }

        protected void btnConfirmRejection_Click(object sender, EventArgs e)
        {
            ProcessInvoices(ProcessType.Reject);
        }

        protected void btnCancelRejection_Click(object sender, EventArgs e)
        {
            ProcessInvoices(ProcessType.CancelRejection);
        }

        private void GetUnauthorizedInvoiceList()
        {
            Lists listEntity = new Lists();
            List<MatchedInvoice> matchList = listEntity.GetUnauthorizedInvoices(((User)Session["CurrentUserVO"]).CustomerID);
            Session[SessionStore.UnAuthorizedListRaw] = matchList;

            if (matchList != null && matchList.Count<MatchedInvoice>() > 0)
            {
                List<MatchedInvoice> invoiceList = new List<MatchedInvoice>(); //a list for populating UI
                string[] matchPatterns = new string[matchList.Count<MatchedInvoice>()]; //match patterns for finding matching pairs in a set
                int matchUniqueKey = 0; //unique match key for a set of invoice-statement pairs

                //iterate through the list of match pairs and creaate a list for display on UI.
                for (int x = 0; x < matchList.Count<MatchedInvoice>(); x++)
                {
                    //consider records not added to the UI list.
                    if (string.IsNullOrEmpty(matchList[x].MatchKey))
                    {
                        //increment unique key and assign it to the current match record.
                        matchUniqueKey++;
                        matchList[x].MatchKey = matchUniqueKey.ToString();

                        //match pattern consisting of invoice and statement ids separated by |
                        matchPatterns[x] = "~" + matchList[x].InvoiceUniqueID + "~|~" + matchList[x].StatementUniqueID + "~";

                        //add the row to new list
                        MatchedInvoice inv = new MatchedInvoice
                        {
                            InvoiceUniqueID = matchList[x].InvoiceUniqueID,
                            InvoiceNumber = matchList[x].InvoiceNumber,
                            InvoiceDate = matchList[x].InvoiceDate,
                            RemitterID = matchList[x].RemitterID,
                            RemitterName = matchList[x].RemitterName,
                            InvoiceAmount = matchList[x].InvoiceAmount,
                            StatementUniqueID = matchList[x].StatementUniqueID,
                            ReferenceNumber = matchList[x].ReferenceNumber,
                            ValueDate = matchList[x].ValueDate,
                            Narration1 = matchList[x].Narration1,
                            StatementAmount = matchList[x].StatementAmount,
                            MatchKey = matchUniqueKey.ToString()
                        };
                        invoiceList.Add(inv);

                        //iterate through the list to find all matches in the set.
                        for (int y = 0; y <= matchList.Count<MatchedInvoice>() - 1; y++)
                        {
                            //check record only if its not added to the UI list.
                            if (string.IsNullOrEmpty(matchList[y].MatchKey))
                            {
                                //separate out invoices and statements
                                string[] matchBreakUp = matchPatterns[x].Split('|');

                                //if the invoice id exists in invoices list then the statement matches against it.
                                if (matchBreakUp[0].IndexOf("~" + matchList[y].InvoiceUniqueID + "~") >= 0)
                                {
                                    //assign unique key to the current match record.
                                    matchList[y].MatchKey = matchUniqueKey.ToString();

                                    //ensure that the statement is not already added to the UI list.
                                    if (matchBreakUp[1].IndexOf("~" + matchList[y].StatementUniqueID + "~") < 0)
                                    {
                                        //append statement to match pattern
                                        matchPatterns[x] += matchList[y].StatementUniqueID + "~";

                                        //if there are more statements than invoices or both equal then add a new row.
                                        if (matchBreakUp[0].Split('~').Length <= matchBreakUp[1].Split('~').Length)
                                        {
                                            MatchedInvoice invStatement = new MatchedInvoice
                                            {
                                                StatementUniqueID = matchList[y].StatementUniqueID,
                                                ReferenceNumber = matchList[y].ReferenceNumber,
                                                ValueDate = matchList[y].ValueDate,
                                                Narration1 = matchList[y].Narration1,
                                                StatementAmount = matchList[y].StatementAmount,
                                                MatchKey = matchUniqueKey.ToString()
                                            };
                                            invoiceList.Add(invStatement);
                                        }
                                        //otherwise add statement details in front of next invoice (statements < invoices)
                                        else
                                        {
                                            //find next blank position for the statement, total row in UI list - difference between number of invoices and number of statements
                                            int nextStatementNumber = invoiceList.Count<MatchedInvoice>() - matchBreakUp[0].Split('~').Length + matchBreakUp[1].Split('~').Length;
                                            invoiceList[nextStatementNumber].StatementUniqueID = matchList[y].StatementUniqueID;
                                            invoiceList[nextStatementNumber].ReferenceNumber = matchList[y].ReferenceNumber;
                                            invoiceList[nextStatementNumber].ValueDate = matchList[y].ValueDate;
                                            invoiceList[nextStatementNumber].Narration1 = matchList[y].Narration1;
                                            invoiceList[nextStatementNumber].StatementAmount = matchList[y].StatementAmount;
                                        }
                                    }
                                }
                                //if the statement id exists in statements list then the invoice matches against it.
                                else if (matchBreakUp[1].IndexOf("~" + matchList[y].StatementUniqueID + "~") >= 0 && string.IsNullOrEmpty(matchList[y].MatchKey))
                                {
                                    //assign unique key to the current match record.
                                    matchList[y].MatchKey = matchUniqueKey.ToString();

                                    //ensure that the invoice is not already added to the UI list.
                                    if (matchBreakUp[0].IndexOf("~" + matchList[y].InvoiceUniqueID + "~") < 0)
                                    {
                                        //append invoice to match pattern
                                        matchPatterns[x] = matchPatterns[x].Replace("~|~", "~" + matchList[y].InvoiceUniqueID + "~|~");

                                        //if there are more invoices than statements or both equal then add a new row.
                                        if (matchBreakUp[1].Split('~').Length <= matchBreakUp[0].Split('~').Length)
                                        {
                                            MatchedInvoice invInvoice = new MatchedInvoice
                                            {
                                                InvoiceUniqueID = matchList[y].InvoiceUniqueID,
                                                InvoiceNumber = matchList[y].InvoiceNumber,
                                                InvoiceDate = matchList[y].InvoiceDate,
                                                RemitterID = matchList[y].RemitterID,
                                                RemitterName = matchList[y].RemitterName,
                                                InvoiceAmount = matchList[y].InvoiceAmount,
                                                MatchKey = matchUniqueKey.ToString()
                                            };
                                            invoiceList.Add(invInvoice);
                                        }
                                        //otherwise add invoice details in front of next statement (invoices < statements)
                                        else
                                        {
                                            //find next blank position for the invoice, total row in UI list - difference between number of statements and number of invoices
                                            int nextInvoiceNumber = invoiceList.Count<MatchedInvoice>() - matchBreakUp[1].Split('~').Length + matchBreakUp[0].Split('~').Length;
                                            invoiceList[nextInvoiceNumber].InvoiceUniqueID = matchList[y].InvoiceUniqueID;
                                            invoiceList[nextInvoiceNumber].InvoiceNumber = matchList[y].InvoiceNumber;
                                            invoiceList[nextInvoiceNumber].InvoiceDate = matchList[y].InvoiceDate;
                                            invoiceList[nextInvoiceNumber].RemitterID = matchList[y].RemitterID;
                                            invoiceList[nextInvoiceNumber].RemitterName = matchList[y].RemitterName;
                                            invoiceList[nextInvoiceNumber].InvoiceAmount = matchList[y].InvoiceAmount;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                Session[SessionStore.UnAuthorizedList] = invoiceList;

                grdAuthList.DataSource = invoiceList;
                grdAuthList.DataBind();

                divButtons.Visible = true;
            }
            else
            {
                Session[SessionStore.UnAuthorizedList] = null;

                grdAuthList.DataSource = null;
                grdAuthList.DataBind();

                //hide buttons, they are not required.
                divButtons.Visible = false;
            }
        }

        private void ShowPopyp(ProcessType processType)
        {
            List<MatchedInvoice> matchList = (List<MatchedInvoice>)Session[SessionStore.UnAuthorizedList];
            if (matchList != null && matchList.Count<MatchedInvoice>() > 0)
            {
                //discard unmarked invoice/statement pairss from the list being authorized/rejected
                StringBuilder unmarkedIDList = new StringBuilder("~");
                foreach (GridViewRow matchRow in grdAuthList.Rows)
                {
                    System.Web.UI.HtmlControls.HtmlInputCheckBox chkSelect = ((System.Web.UI.HtmlControls.HtmlInputCheckBox)matchRow.Cells[0].FindControl("chkSelect"));
                    if (!chkSelect.Checked)
                    {
                        unmarkedIDList.Append(matchList[matchRow.RowIndex].MatchKey + "~");
                    }
                }
                //if unmarked items found then remove from list
                if (!unmarkedIDList.ToString().Equals("~"))
                {
                    for (int x = matchList.Count<MatchedInvoice>() - 1; x >= 0; x--)
                    {
                        if (unmarkedIDList.ToString().IndexOf("~" + matchList[x].MatchKey.ToString() + "~") >= 0)
                        {
                            matchList.RemoveAt(x);
                        }
                    }
                }

                //the remainder is marked for authorization/rejection, create a list for display
                Session[SessionStore.MarkedList] = matchList;

                switch (processType)
                {
                    case ProcessType.Authorize:
                        grdConfirmAuthorization.DataSource = matchList;
                        grdConfirmAuthorization.DataBind();
                        if (matchList != null && matchList.Count<MatchedInvoice>() > 0)
                        {
                            btnConfirmAuthorization.Visible = true;
                            btnCancelAuthorization.Text = "Cancel Authorization";
                        }
                        else
                        {
                            btnConfirmAuthorization.Visible = false;
                            btnCancelAuthorization.Text = "Close";
                        }
                        AuthorizationConfirmationPopup.Show();
                        break;

                    case ProcessType.Reject:
                        grdConfirmRejection.DataSource = matchList;
                        grdConfirmRejection.DataBind();
                        if (matchList != null && matchList.Count<MatchedInvoice>() > 0)
                        {
                            btnConfirmRejection.Visible = true;
                            btnCancelRejection.Text = "Cancel Rejection";
                        }
                        else
                        {
                            btnConfirmRejection.Visible = false;
                            btnCancelRejection.Text = "Close";
                        }
                        RejectionConfirmationPopup.Show();
                        break;
                }
            }
        }

        private void ProcessInvoices(ProcessType processType)
        {
            if (processType == ProcessType.Authorize || processType == ProcessType.Reject)
            {//confirmation
                //list of invoice/statement pairs for confirmation
                List<MatchedInvoice> confirmList = (List<MatchedInvoice>)Session[SessionStore.MarkedList];

                //prepare a sstring with match keys of all confirmed entries
                StringBuilder confirmedList = new StringBuilder("~");
                foreach (MatchedInvoice inv in confirmList)
                {
                    if (confirmedList.ToString().IndexOf("~" + inv.MatchKey.ToString() + "~") < 0)
                    {
                        confirmedList.Append(inv.MatchKey + "~");
                    }
                }

                List<MatchedInvoice> matchList = (List<MatchedInvoice>)Session[SessionStore.UnAuthorizedListRaw];

                for (int x = matchList.Count<MatchedInvoice>() - 1; x >= 0; x--)
                {
                    if (confirmedList.ToString().IndexOf("~" + matchList[x].MatchKey.ToString() + "~") < 0)
                    {
                        matchList.RemoveAt(x);
                    }
                }

                ReconcileEntity recon = new ReconcileEntity();
                switch (processType)
                {
                    case ProcessType.Authorize:
                        recon.AuthorizeInvoices(matchList, ((User)Session["CurrentUserVO"]).CustomerID, ((User)Session["CurrentUserVO"]).UserID);
                        grdConfirmAuthorization.DataSource = null;
                        grdConfirmAuthorization.DataBind();
                        AuthorizationConfirmationPopup.Hide();
                        break;

                    case ProcessType.Reject:
                        recon.RejectInvoices(matchList, ((User)Session["CurrentUserVO"]).CustomerID, ((User)Session["CurrentUserVO"]).UserID);
                        grdConfirmRejection.DataSource = null;
                        grdConfirmRejection.DataBind();
                        RejectionConfirmationPopup.Hide();
                        break;
                }
            }
            else
            {//cancellation
                switch (processType)
                {
                    case ProcessType.CancelAuthorization:
                        grdConfirmAuthorization.DataSource = null;
                        grdConfirmAuthorization.DataBind();
                        AuthorizationConfirmationPopup.Hide();
                        break;

                    case ProcessType.CancelRejection:
                        grdConfirmRejection.DataSource = null;
                        grdConfirmRejection.DataBind();
                        RejectionConfirmationPopup.Hide();
                        break;
                }
            }

            //get fresh list after database update and update UI
            GetUnauthorizedInvoiceList();
        }
    }
}